using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Framework.Audio
{
    public class BaseAudioManager : SingletonMono<BaseAudioManager>
    {
        private static readonly int _MAX_TRACK = 20;

        #region 对象池属性

        protected Queue<AudioTrack> _AudioPool;
        private float timer = 0; //计时器

        #endregion

        
        protected List<AudioTrack> _AudioPlaying;

        
        protected Dictionary<AudioSourceType, float>  _GlobalVolumeOffset; //全局音频 音量缩放系数
        protected Dictionary<string, float>           _GroupVolumeOffset;  //音频组   音量缩放系数
        
        
        private bool _isActiveUpdater = true;

        protected override void Init()
        {
            base.Init();
            this._AudioPool               = new Queue<AudioTrack> ();
            this._AudioPlaying            = new List<AudioTrack> ();
            this._GlobalVolumeOffset      = new Dictionary<AudioSourceType, float> ();
            this._GroupVolumeOffset       = new Dictionary<string, float> ();
        }

        /*protected BaseAudioManager ()
        {
            this._AudioPool               = new Queue<AudioTrack> ();
            this._AudioPlaying            = new List<AudioTrack> ();
            this._GlobalVolumeOffset      = new Dictionary<AudioSourceType, float> ();
            this._GroupVolumeOffset       = new Dictionary<string, float> ();
        }*/
        
        #region 对象池


        protected virtual void DoUpdate ()
        {
            // UtilProfiler.Instance.Start("AudioManager");
            if (this._isActiveUpdater == false)
            {
                return;
            }

            for (var i = this._AudioPlaying.Count - 1; i >= 0; i--)
            {
                if (!this._AudioPlaying[i].IsDone) continue;
                
                var audioTrack = this._AudioPlaying[i];
                this._AudioPlaying.RemoveAt (i);
                audioTrack.Clear ();
                    
                if (this._AudioPool.Count < _MAX_TRACK)
                    this._AudioPool.Enqueue(audioTrack);
                else
                    Destroy (audioTrack.gameObject);
            }
        }

        
        
     
      


        public AudioTrack GetAudioTrack(AudioSourceType type)
        {
            
            AudioTrack AudioTrack = null;

            //拿走该对象
            AudioTrack = _AudioPool.Count > 0 ? _AudioPool.Dequeue() : CreateAudioTrackObject(); //若没有该类型


            //再次核实是否转化成功
            if (AudioTrack == null)
            {
                Debug.LogError("为空");
                AudioTrack = CreateAudioTrackObject();
            }

            //将该对象显示
            //gameObj.SetActive(true);
            AudioTrack.Initial(type);
            return AudioTrack;
        }

        private AudioTrack CreateAudioTrackObject()
        {
            //罗  代码
            /*var obj         = new GameObject { name = $"[{audioType}]Audio_Track" };
            var audioSource = obj.AddComponent<AudioSource> ();
            obj.transform.SetParent (this.transform);
            return obj.AddComponent<AudioTrack> ().Init (audioSource,  audioType , this.AudioSourceHandler);*/
            
            GameObject obj = GameObject.Instantiate(this.gameObject);
            obj.transform.SetParent(this.transform);
            var audioTrack = obj.AddComponent<AudioTrack>(); 
            audioTrack.OnCreate();
            return audioTrack;
        }


        /// <summary>
        /// 获取指定类型正在播放的AudioSource
        /// </summary>
        /// <param name="audioType"></param>
        /// <returns></returns>
        protected List<AudioTrack> GetPlayingAudio (AudioSourceType audioType)
        {
            return this._AudioPlaying.Where(audioPlayer => audioPlayer.AudioType == audioType).ToList();
        }

        #endregion

        #region 音量

        
        /// <summary>
        /// 按类型设置音量
        /// </summary>
        /// <param name="audioType"></param>
        /// <param name="volume"></param>
        /// <param name="time"></param>
        public void SetGlobalVolume (AudioSourceType audioType, float volume , float time = 0)
        {
            ushort audioShort = (ushort)audioType;
            this._GlobalVolumeOffset[audioType] = Mathf.Clamp (volume, 0, 1);
            
            //var audios = this.GetPlayingAudio (audioType);
            foreach (var audioTrack in this._AudioPlaying.Where(audioPlayer => audioPlayer.AudioType == audioType))
            {
                audioTrack.SetVolumeOffset(GetVolumeOffset (audioType , audioTrack.AudioGroup) , time);
            }
        }
        /// <summary>
        /// 按组设置音量
        /// </summary>
        /// <param name="audioGroup"></param>
        /// <param name="volume"></param>
        /// <param name="time"></param>
        public void SetGroupVolume (string audioGroup, float volume , float time = 0)
        {
            this._GroupVolumeOffset[audioGroup] = Mathf.Clamp (volume, 0, 1);//保存
            foreach (var audioPlayer in this._AudioPlaying)
            {
                if (audioPlayer.AudioGroup == audioGroup)
                {
                    audioPlayer.SetVolumeOffset(GetVolumeOffset (audioPlayer.AudioType , audioGroup) , time);
                }
            }
        }

        /// <summary>
        /// 获取影响的偏移值
        /// </summary>
        /// <param name="audioType"></param>
        /// <param name="audioGroup"></param>
        /// <returns></returns>
        private float GetVolumeOffset (AudioSourceType audioType , string audioGroup)
        {
            var volume = 1f;
            if (!this._GlobalVolumeOffset.ContainsKey (audioType))
            {
                //默认值
                this._GlobalVolumeOffset[audioType] = 1;
            }

            volume *= this._GlobalVolumeOffset[audioType];
            if (!string.IsNullOrEmpty (audioGroup))
            {
                if ( !this._GroupVolumeOffset.ContainsKey (audioGroup))
                {
                    this._GroupVolumeOffset[audioGroup] = 1;
                }

                volume *= this._GroupVolumeOffset[audioGroup];
            }

            return volume;
        }

        #endregion


        #region 播放

        /// <summary>
        /// 基础播放
        /// </summary>
        /// <param name="audioClip"></param>
        /// <param name="volume"></param>
        /// <param name="spatialBlend"></param>
        /// <param name="inTime"></param>
        /// <param name="audioType"></param>
        /// <param name="audioGroup"></param>
        /// <param name="isLoop"></param>
        /// <returns></returns>
        public AudioTrack BasePlay (AudioClip audioClip, float volume = 1, float spatialBlend = 0, float inTime = 0,
        AudioSourceType                    audioType = AudioSourceType.BGM, string audioGroup = null, bool  isLoop       = false)
        {
            if (audioClip==null)
            {
                return null;
            }

            var    player     = this.GetAudioTrack(audioType);
            if (!this._GlobalVolumeOffset.ContainsKey (audioType))
            {
                //默认值
                this._GlobalVolumeOffset[audioType] = 1;
            }    
            
            player.AudioSource.spatialBlend = spatialBlend;
            player.PlayAudio(audioClip, audioGroup, this.GetVolumeOffset (audioType , audioGroup), volume, inTime, isLoop);
            this._AudioPlaying.Add (player);
            return player;
        }

        #region 暂停

        

     
        
         /// <summary>
        /// 按照音频类型暂停或者播放
        /// </summary>
        /// <param name="audioType"></param>
        /// <param name="isPause"></param>
        /// <param name="outTime"></param>
        public void PausePlayers (AudioSourceType audioType, bool isPause, float outTime = 0)
        {
            //ushort audioShort = (ushort)audioType;
            //var  players   = this.GetPlayingAudio (audioType);
            foreach (var audioPlayer in this._AudioPlaying.Where(audioPlayer => audioPlayer.AudioType == audioType))
            {
                if (isPause)
                    audioPlayer.PauseAudio(outTime);
                else
                    audioPlayer.ReplayAudio(outTime);
            }
        }

        /// <summary>
        /// 按照音频组暂停或者播放
        /// </summary>
        /// <param name="audioGroup"></param>
        /// <param name="isPause"></param>
        /// <param name="outTime"></param>
        public void PausePlayers (string audioGroup, bool isPause, float outTime = 0)
        {
            if (string.IsNullOrEmpty (audioGroup))
            {
                PauseAllPlayer (isPause , outTime);
                return;
            }

            foreach (var audioPlayer in this._AudioPlaying.Where(audioPlayer => audioPlayer.AudioGroup == audioGroup))
            {
                if (isPause)
                    audioPlayer.PauseAudio(outTime);
                else
                    audioPlayer.ReplayAudio(outTime);
            }
        }
        
        public void PauseAllPlayer (bool isPause, float outTime = 0)
        {
            foreach (var audioPlayer in this._AudioPlaying)
            {
                if (isPause)
                    audioPlayer.PauseAudio(outTime);
                else
                    audioPlayer.ReplayAudio(outTime);
            }
        }
        
        #endregion


        #region 删除

        

   
        /// <summary>
        /// 根据clip名称删除音源
        /// </summary>
        /// <param name="audioName"></param>
        /// <param name="outTime"></param>
        public void KillPlayers (string audioName, float outTime = 0)
        {
            foreach (var audioPlayer in this._AudioPlaying.Where(audioPlayer => audioPlayer.AudioClipName == audioName))
            {
                audioPlayer.Kill (outTime);
            }
        }

        public void KillPlayers (AudioSourceType audioGroup, float outTime = 0)
        {
            //var    players    = this.GetPlayingAudio (audioGroup);
            foreach (var audioPlayer in this._AudioPlaying.Where(audioPlayer => audioPlayer.AudioType == audioGroup))
            {
                audioPlayer.Kill (outTime);
            }
        }

        public void KillAllPlayer (float outTime = 0)
        {
            foreach (var audioPlayer in this._AudioPlaying)
            {
                audioPlayer.Kill (outTime);
            }
        }

       
        #endregion
        
        
        

        #endregion
        
        
        
        /// <summary>
        /// 程序暂停时
        /// </summary>
        /// <param name="pauseStatus"></param>
        private void OnApplicationPause (bool pauseStatus)
        {
            this._isActiveUpdater = !pauseStatus;
        }
        
        
        
    }
    
}